﻿#include "rtcservice.h"
#include <QBuffer>
#include <QDebug>
#include <QMetaObject>
#include "utils.h"
#include "alirtceventhandler.h"
#include "serialization.h"

RTCService::RTCService(QObject *parent, const QString &serverName)
    : QObject(parent), server(new QLocalServer(this))
{
    // 只有当 serverName 不为空时才启动 socket 服务器
    if (!serverName.isEmpty()) {
        if (!server->listen(serverName)) {
            qCritical() << "[RTC] Unable to start the local server:" << server->errorString();
        } else {
            qDebug() << "[RTC] Local server started, listening on" << serverName;
        }
        
        connect(server, &QLocalServer::newConnection, this, &RTCService::onNewConnection);
    } else {
        qDebug() << "[RTC] RTCService created without socket server (internal mode)";
    }

    qRegisterMetaType<RTCEngineCallback>("RTCEngineCallback");
}

RTCService::~RTCService()
{
    sockets.clear();

    foreach (auto var, sockets) {
            var->disconnectFromServer();
    }

    // 关闭服务器
    if (server->isListening()) {
        server->close();
    }

    if (engine) {
        engine->SetEngineEventListener(nullptr);
        // NOTE 该方法为同步调用，需要等待内部资源释放之后才能执行其他方法
        RTC3::RtcEngine::Destroy(engine);
        engine = nullptr;
    }

    audioDeviceManager = nullptr;
    videoDeviceManager = nullptr;

    if(eventhandler){
        delete eventhandler;
        eventhandler = nullptr;
    }
}

void RTCService::onNewConnection()
{
    // 接受新连接
    QLocalSocket *socket = server->nextPendingConnection();
    if (socket) {
        qDebug() << "[RTC] New connection established";
        if(sockets.size() == 1){
             muteSocket = socket;
        }

        if(sockets.size() > 2)
            qCritical() << "[RTC] more than 2 client connected!";

        sockets.push_back(socket);

        // 连接套接字的信号到相应的槽函数
        connect(socket, &QLocalSocket::readyRead, this, &RTCService::onReadyRead);
        connect(socket, &QLocalSocket::disconnected, this, &RTCService::onDisconnected);
    }
}

void RTCService::onReadyRead()
{
    // 读取数据并处理请求
    QLocalSocket *socket = qobject_cast<QLocalSocket*>(sender());
    if (!socket) {
        qDebug() << "[RTC] Error: No socket available.";
        return;
    }

    buffer.append(socket->readAll());

    processBuffer(socket);
}

void RTCService::processBuffer(QLocalSocket *socket) {
    static const int headerSize = 1 + sizeof(qint32);

    while (buffer.size() >= headerSize) {
        QDataStream stream(buffer);
        stream.setVersion(QDataStream::Qt_5_0);

        qint8 flag;
        qint32 packetSize;

        // 预检数据头
        stream >> flag >> packetSize;

        if (buffer.size() < headerSize + packetSize) {
            qDebug() << "[RTC] Not enough data to read entire packet, waiting for more data.";
            return; // 数据不足以处理完整包，等待下次读取
        }

        buffer.remove(0, headerSize); // 移除头部
        QByteArray packetData = buffer.mid(0, packetSize);
        buffer.remove(0, packetSize); // 移除已处理的包

        // 处理数据包
        RTCEngineRequest request = deserializeRequest(packetData);
        RTCEngineResponse response;
        processRequest(socket,request, response);

        QByteArray serializedResponse = serializeResponse(response);
//        socket->write(serializedResponse);

        if(socket->write(serializedResponse) != serializedResponse.size()){
            qDebug() << "[RTC] Could not send all data to server!";
        }

        socket->flush();
        qDebug() << "[RTC] Processed request[" << RTCEngineCommand::commandToString(request.command) << "_" << request << "]" << "and sent response ["<< response << "]";
    }
}


void RTCService::onDisconnected()
{
    // 处理断开连接
    QLocalSocket *socket = qobject_cast<QLocalSocket*>(sender());
    if (socket) {
        qDebug() << "[RTC] Connection disconnected";

        int indexToRemove = -1;
        for (int i = 0; i < sockets.size(); ++i) {
            if (sockets[i] == socket) { // 这里的比较仅作为示例
                indexToRemove = i;
                break;
            }
        }

        if(indexToRemove != -1){
            sockets.remove(indexToRemove);
        }

        // 删除套接字对象（Qt会自动处理内存）
        socket->deleteLater();

        if(sockets.size() == 0){
            qDebug() << "[RTC] With nothing to worry about, I will eventually pass away!";
            emit exit();
        }
    }
}

QByteArray RTCService::serializeResponse(const RTCEngineResponse &response, int flag) const {
    QByteArray data;
    QDataStream out(&data, QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_5_0);

    // 占位写入标志位和长度
    qint32 placeholder = 0;
    out << (qint8)flag << placeholder;

    // 序列化 response 对象
    out << response;

    // 计算数据长度并回填
    qint32 dataSize = data.size() - sizeof(qint8) - sizeof(qint32); // 总长度减去标志位和长度本身的空间
    QDataStream sizeStream(&data, QIODevice::WriteOnly);
    sizeStream.device()->seek(1); // 跳过标志位
    sizeStream << dataSize;

    return data;
}

RTCEngineRequest RTCService::deserializeRequest(const QByteArray &requestData) const
{
    if (requestData.isEmpty()) {
        qDebug() << "[RTC] Invalid request data: empty data";
        return RTCEngineRequest(RTCEngineCommand::Engine_Invalid, QVector<QVariant>());
    }

    QDataStream in(requestData);
    in.setVersion(QDataStream::Qt_5_0);

    RTCEngineRequest request;
    in >> request; // 使用已定义的 `>>` 操作符重载来反序列化

    if (in.status() != QDataStream::Ok) {
        qDebug() << "[RTC] Failed to deserialize request: invalid data format";
        return RTCEngineRequest(RTCEngineCommand::Engine_Invalid, QVector<QVariant>());
    }

    return request;
}




void RTCService::processRequest(QLocalSocket *socket, const RTCEngineRequest &request, RTCEngineResponse& response)
{
    QString errorMessage;
    int ret = -1;

    response.command = request.command;

    // 处理请求
    switch (request.command) {
        // RtcEngine 接口
        case RTCEngineCommand::Engine_Create:
            engine = RTC3::RtcEngine::Create(nullptr);
            if (engine) {
                eventhandler = new AliRtcEventHandler(this);
                //TODO
                engine->SetEngineEventListener(eventhandler);
                audioDeviceManager = engine->GetAudioDeviceManager();
                videoDeviceManager = engine->GetVideoDeviceManager();
//                audioMixingManager = engine->GetAudioMixingManager();
            }
            break;
        case RTCEngineCommand::Engine_Destroy:
            break;
        case RTCEngineCommand::Engine_GetSDKVersion:
            response.results.append(QString(engine->GetSDKVersion()));
            break;
        case RTCEngineCommand::Engine_SetLogDirPath:
            ret = engine->SetLogDirPath(RETURN_STRING(request).toStdString().c_str());
            response.results.append(ret);
            break;
        case RTCEngineCommand::Engine_GetLogDirPath:
            break;
        case RTCEngineCommand::Engine_SetLogLevel:
            break;
        case RTCEngineCommand::Engine_GetErrorDescription:
            break;
        case RTCEngineCommand::Engine_SetEngineEventListener:
            break;
        case RTCEngineCommand::Engine_GetAudioMixingManager:
            break;
        case RTCEngineCommand::Engine_GetAudioDeviceManager:
            break;
        case RTCEngineCommand::Engine_GetVideoDeviceManager:
            break;
        case RTCEngineCommand::Engine_GetCurrentConnectionStatus:
            break;
        case RTCEngineCommand::Engine_JoinChannel:
            if (engine){
                ret = engine->JoinChannel(desRtcEngineAuthInfo(RETURN_STRING(request)), "");
                response.results.append(ret);
            }
            break;
        case RTCEngineCommand::Engine_LeaveChannel:
            engine->LeaveChannel();
            break;
        case RTCEngineCommand::Engine_GetOnlineRemoteUsers:
            break;
        case RTCEngineCommand::Engine_GetUserInfo:
            break;
        case RTCEngineCommand::Engine_IsUserOnline:
            break;
        case RTCEngineCommand::Engine_IsInCall:
            response.results.append(engine->IsInCall());
            break;
        case RTCEngineCommand::Engine_PublishLocalVideoStream:
            response.results.append(engine->PublishLocalVideoStream(RETURN_BOOL(request)));
            break;
        case RTCEngineCommand::Engine_PublishLocalAudioStream:
            response.results.append(engine->PublishLocalAudioStream(RETURN_BOOL(request)));
            break;
        case RTCEngineCommand::Engine_IsLocalVideoStreamPublished:
            response.results.append(engine->IsLocalVideoStreamPublished());
            break;
        case RTCEngineCommand::Engine_IsScreenSharePublished:
            break;
        case RTCEngineCommand::Engine_IsLocalAudioStreamPublished:
            response.results.append(engine->IsLocalAudioStreamPublished());
            break;
        case RTCEngineCommand::Engine_MuteLocalVideo:
            break;
        case RTCEngineCommand::Engine_MuteLocalAudio:
            response.results.append(engine->MuteLocalAudio(RETURN_BOOL(request)));
            break;
        case RTCEngineCommand::Engine_StartScreenShareByDesktopId:
            break;
        case RTCEngineCommand::Engine_StartScreenShareByWindowId:
            break;
        case RTCEngineCommand::Engine_UpdateScreenShareConfig:
            break;
        case RTCEngineCommand::Engine_StopScreenShare:
            break;
        case RTCEngineCommand::Engine_GetScreenShareSourceInfo:
            break;
        case RTCEngineCommand::Engine_GetCurrentScreenShareSourceId:
            break;
        case RTCEngineCommand::Engine_SubscribeAllRemoteAudioStreams:
            response.results.append(engine->SubscribeAllRemoteAudioStreams(RETURN_BOOL(request)));
            break;
        case RTCEngineCommand::Engine_SubscribeAllRemoteVideoStreams:
            response.results.append(engine->SubscribeAllRemoteVideoStreams(RETURN_BOOL(request)));
            break;
        case RTCEngineCommand::Engine_SubscribeRemoteVideoStream:
            engine->SubscribeRemoteVideoStream(RETURN_STRING(request).toStdString().c_str(),
                                               desFromJSONStringEnum(RETURN_STRING_INDEX(request,1),desRtcEngineVideoTrack),RETURN_BOOL_INDEX(request,2));
            break;
        case RTCEngineCommand::Engine_SetRemoteVideoStreamType:
            break;
        case RTCEngineCommand::Engine_SetRemoteDefaultVideoStreamType:
            break;
        case RTCEngineCommand::Engine_EnableLocalVideo:
            break;
        case RTCEngineCommand::Engine_EnableBeautyFace:
        {
            RtcEngineBeautyFaceOptions opt = desFromJSONString(RETURN_STRING_INDEX(request,1),desRtcEngineBeautyFaceOptions);
            ret = engine->EnableBeautyFace(RETURN_BOOL(request),opt);
            response.results.append(ret);
        }
            break;
        case RTCEngineCommand::Engine_EnableVirtualBackground:
            break;
        case RTCEngineCommand::Engine_SetVideoEnhance:
            break;
        case RTCEngineCommand::Engine_SetVideoDenoise:
            break;
        case RTCEngineCommand::Engine_SetAudioDenoise:
            break;
        case RTCEngineCommand::Engine_SetVideoEncoderConfiguration:
        {
                RtcEngineVideoEncoderConfiguration config = desFromJSONString(RETURN_STRING(request),desRtcEngineVideoEncoderConfiguration);
                engine->SetVideoEncoderConfiguration(config);
        }
            break;
        case RTCEngineCommand::Engine_SetScreenShareEncoderConfiguration:
            break;
        case RTCEngineCommand::Engine_SetLocalViewConfig:
            ret = engine->SetLocalViewConfig(desFromJSONString(RETURN_STRING(request),desRtcEngineVideoCanvas),
                   desFromJSONStringEnum(RETURN_STRING_INDEX(request,1),desRtcEngineVideoTrack));
            response.results.append(ret);
            break;
        case RTCEngineCommand::Engine_SetRemoteViewConfig:
            ret = engine->SetRemoteViewConfig(desFromJSONString(RETURN_STRING(request),desRtcEngineVideoCanvas),
                                    RETURN_STRING_INDEX(request,1).toStdString().c_str(),
                                    desFromJSONStringEnum(RETURN_STRING_INDEX(request,2),desRtcEngineVideoTrack));
            response.results.append(ret);
            break;
        case RTCEngineCommand::Engine_UpdateViewConfig:
            break;
        case RTCEngineCommand::Engine_StartPreview:
            response.results.append(engine->StartPreview());
            break;
        case RTCEngineCommand::Engine_StopPreview:
            response.results.append(engine->StopPreview());
            break;
        case RTCEngineCommand::Engine_RegisterVideoFrameObserver:
            break;
        case RTCEngineCommand::Engine_EnableVideoFrameObserver:
            break;
        case RTCEngineCommand::Engine_SetAudioProfile:
            ret = engine->SetAudioProfile(desFromJSONStringEnum(RETURN_STRING_INDEX(request,1),desRtcEngineAudioProfile),
                                    desFromJSONStringEnum(RETURN_STRING_INDEX(request,1),desRtcEngineAudioScenario));
            response.results.append(ret);
            break;
        case RTCEngineCommand::Engine_EnableAudioVolumeIndication:
            break;
        case RTCEngineCommand::Engine_RegisterAudioFrameObserver:
            break;
        case RTCEngineCommand::Engine_EnableAudioFrameObserver:
            break;
        case RTCEngineCommand::Engine_SetExternalAudioSource:
            break;
        case RTCEngineCommand::Engine_PushExternalAudioFrame:
            break;
        case RTCEngineCommand::Engine_SetExternalAudioRender:
            break;
        case RTCEngineCommand::Engine_PushExternalAudioRenderFrame:
            break;
        case RTCEngineCommand::Engine_EnableCustomAudioCapture:
            break;
        case RTCEngineCommand::Engine_SendCustomAudioCaptureFrame:
            break;
        case RTCEngineCommand::Engine_EnableCustomAudioRender:
            break;
        case RTCEngineCommand::Engine_GetCustomAudioRenderFrame:
            break;
        case RTCEngineCommand::Engine_SetPlayoutSignalVolume:
            break;
        case RTCEngineCommand::Engine_GetPlayoutSignalVolume:
            break;
        case RTCEngineCommand::Engine_SetExternalVideoSource:
            break;
        case RTCEngineCommand::Engine_PushExternalVideoFrame:
            break;
        case RTCEngineCommand::Engine_StartRecord:
            ret = engine->StartRecord(desFromJSONString(RETURN_STRING(request),desRtcEngineRecordOptions),RETURN_STRING_INDEX(request,1).toStdString().c_str(),
                                RETURN_STRING_INDEX(request,2).toStdString().c_str());
            response.results.append(ret);
            break;
        case RTCEngineCommand::Engine_UpdateRecordLayout:
            break;
        case RTCEngineCommand::Engine_PauseRecord:
            break;
        case RTCEngineCommand::Engine_ResumeRecord:
            break;
        case RTCEngineCommand::Engine_StopRecord:
            engine->StopRecord();
            break;
        case RTCEngineCommand::Engine_SnapshotVideo:
            break;
        case RTCEngineCommand::Engine_SendMediaExtensionMsg:
            break;

        // RtcEngineVideoDeviceManager 接口
        case RTCEngineCommand::VideoDM_GetCameraList:
            response.results.append(sToJSONString(videoDeviceManager->GetCameraList(),sRtcEngineDeviceInfoList));
            break;
        case RTCEngineCommand::VideoDM_GetCurrentCameraName:
            break;
        case RTCEngineCommand::VideoDM_GetCurrentCameraID:
            break;
        case RTCEngineCommand::VideoDM_SetCurrentCameraName:
            response.results.append(videoDeviceManager->SetCurrentCameraName(RETURN_STRING(request).toStdString().c_str()));
            break;
        case RTCEngineCommand::VideoDM_SetCurrentCameraID:
            response.results.append(videoDeviceManager->SetCurrentCameraID(RETURN_STRING(request).toStdString().c_str()));
            break;
        case RTCEngineCommand::VideoDM_IsCameraOn:
            response.results.append(videoDeviceManager->IsCameraOn());
            break;
        case RTCEngineCommand::VideoDM_SwitchCamera:
            break;
        case RTCEngineCommand::VideoDM_SetCameraZoom:
            break;
        case RTCEngineCommand::VideoDM_SetCameraFlash:
            break;
        case RTCEngineCommand::VideoDM_IsCameraFocusPointSupported:
            break;
        case RTCEngineCommand::VideoDM_SetCameraFocusPoint:
            break;
        case RTCEngineCommand::VideoDM_IsCameraExposurePointSupported:
            break;
        case RTCEngineCommand::VideoDM_SetCameraExposurePoint:
            break;
        case RTCEngineCommand::VideoDM_SetDeviceOrientationMode:
            break;

        // RtcEngineAudioDeviceManager 接口
        case RTCEngineCommand::AudioDM_GetRecordingDeviceList:
            response.results.append(sToJSONString(audioDeviceManager->GetRecordingDeviceList(),sRtcEngineDeviceInfoList));
            break;
        case RTCEngineCommand::AudioDM_GetCurrentRecordingDeviceId:
            break;
        case RTCEngineCommand::AudioDM_SetCurrentRecordingDeviceId:
            response.results.append(audioDeviceManager->SetCurrentRecordingDeviceId(RETURN_STRING(request).toStdString().c_str()));
            break;
        case RTCEngineCommand::AudioDM_GetPlayoutDeviceList:
            response.results.append(sToJSONString(audioDeviceManager->GetPlayoutDeviceList(),sRtcEngineDeviceInfoList));
            break;
        case RTCEngineCommand::AudioDM_GetCurrentPlayoutDeviceId:
            break;
        case RTCEngineCommand::AudioDM_SetCurrentPlayoutDeviceId:
            response.results.append(audioDeviceManager->SetCurrentPlayoutDeviceId(RETURN_STRING(request).toStdString().c_str()));
            break;
        case RTCEngineCommand::AudioDM_SetRecordingDeviceVolume:
            response.results.append(audioDeviceManager->SetRecordingDeviceVolume(RETURN_INT(request)));
            break;
        case RTCEngineCommand::AudioDM_GetRecordingDeviceVolume:
            response.results.append(audioDeviceManager->GetRecordingDeviceVolume());
            break;
        case RTCEngineCommand::AudioDM_SetPlayoutDeviceVolume:
            response.results.append(audioDeviceManager->SetPlayoutDeviceVolume(RETURN_INT(request)));
            break;
        case RTCEngineCommand::AudioDM_GetPlayoutDeviceVolume:
            response.results.append(audioDeviceManager->GetPlayoutDeviceVolume());
            break;
        case RTCEngineCommand::AudioDM_SetRecordingDeviceMute:
            break;
        case RTCEngineCommand::AudioDM_SetRecordingDataMute:
            break;
        case RTCEngineCommand::AudioDM_GetRecordingDeviceMute:
            break;
        case RTCEngineCommand::AudioDM_SetPlayoutDeviceMute:
            break;
        case RTCEngineCommand::AudioDM_GetPlayoutDeviceMute:
            break;
        case RTCEngineCommand::AudioDM_StartRecordingDeviceTest:
            response.results.append(audioDeviceManager->StartRecordingDeviceTest());
            break;
        case RTCEngineCommand::AudioDM_StopRecordingDeviceTest:
            response.results.append(audioDeviceManager->StopRecordingDeviceTest());
            break;
        case RTCEngineCommand::AudioDM_StartPlayoutDeviceTest:
            response.results.append(audioDeviceManager->StartPlayoutDeviceTest(RETURN_STRING(request).toStdString().c_str()));
            break;
        case RTCEngineCommand::AudioDM_StopPlayoutDeviceTest:
             response.results.append(audioDeviceManager->StopPlayoutDeviceTest());
            break;
        case RTCEngineCommand::AudioDM_EnableAudioLevelObserver:
            break;

        case RTCEngineCommand::AudioDM_EnableSystemAudio:
            response.results.append(audioDeviceManager->EnableSystemAudio(true));
            break;

        case RTCEngineCommand::AudioDM_DisableSystemAudio:
            response.results.append(audioDeviceManager->EnableSystemAudio(false));
            break;

        case RTCEngineCommand::AudioDM_StartAudioPlayer:
            response.results.append(audioDeviceManager->StartAudioPlayer());
            break;

        case RTCEngineCommand::AudioDM_StartAudioCapture:
            response.results.append(audioDeviceManager->StartAudioCapture());
            break;

        case RTCEngineCommand::Enable_AI_Denoise:
            {
                ding::rtc::RtcEngineAudioDenoiseOptions options;
                options.mode =
                  ding::rtc::RtcEngineAudioDenoiseMode::RtcEngineAudioDenoiseEnhance;

                response.results.append(engine->SetAudioDenoise(options));
                break;
            }

        default:
            break;
    }
}

QByteArray RTCService::serializeCallback(const RTCEngineCallback &callback, int flag) const {
    QByteArray data;
    QDataStream out(&data, QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_5_0);

    // 占位写入标志位和长度
    qint32 placeholder = 0;
    out << (qint8)flag << placeholder;

    // 序列化 callback 对象
    out << callback;

    // 计算数据长度并回填
    qint32 dataSize = data.size() - sizeof(qint8) - sizeof(qint32); // 总长度减去标志位和长度本身的空间
    QDataStream sizeStream(&data, QIODevice::WriteOnly);
    sizeStream.device()->seek(1); // 跳过标志位
    sizeStream << dataSize;

    return data;
}

void RTCService::processCallback(RTCEngineCallback callback) {
    if(!muteSocket || muteSocket->state() != QLocalSocket::ConnectedState){
        qDebug() << "[RTC] muteSocket invalid!!!";
        return;
    }

    int length = muteSocket->write(serializeCallback(callback));
    muteSocket->flush();
}
